name: CI

on: [ push, pull_request ]

jobs:
  build-linux:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: |
          bake --strict

  build-macos:
    runs-on: macOS-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: |
          bake --strict

  build-windows:
    runs-on: windows-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      - uses: ilammy/msvc-dev-cmd@v1
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          cd bake\build-Windows
          nmake
          cd ..
          ./bake setup --local

      - name: build flecs (debug)
        run: bake/bake --strict --cfg debug
        
      - name: build flecs (release)  
        run: bake/bake --strict --cfg release

      - name: build examples (debug)
        run: bake/bake examples --strict --cfg debug

      - name: build examples (release)
        run: bake/bake examples --strict --cfg debug

  build-msys:
    runs-on: windows-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        include:
          - { sys: mingw64 }
          - { sys: mingw32 }
          - { sys: ucrt64 }
          - { sys: clang64 }

    defaults:
      run:
        shell: msys2 {0}

    steps:
      - uses: actions/checkout@v4
      - uses: msys2/setup-msys2@v2
        with:
          msystem: ${{matrix.sys}}
          update: true
          install: >-
            curl
            git
          pacboy: >-
            toolchain:p
            cmake:p

      - name: create cmake build folders
        run: |
          mkdir cmake_build
          mkdir examples/c/cmake_build
          mkdir examples/cpp/cmake_build

      - name: build flecs
        working-directory: cmake_build
        run: |
          cmake -G "MinGW Makefiles" -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c examples
        working-directory: examples/c/cmake_build
        run: |
          cmake -G "MinGW Makefiles" -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c++ examples
        working-directory: examples/cpp/cmake_build
        run: |
          cmake -G "MinGW Makefiles" -DFLECS_STRICT=ON ..
          cmake --build . -j 4

  build:
    needs: build-linux
    runs-on: ${{ matrix.target.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        target:
          - { os: ubuntu-20.04, cc: gcc-7,  cxx: g++-7 }
          - { os: ubuntu-20.04, cc: gcc-8,  cxx: g++-8 }
          - { os: ubuntu-20.04, cc: gcc-9,  cxx: g++-9 }
          - { os: ubuntu-20.04, cc: gcc-10, cxx: g++-10 }
          - { os: ubuntu-20.04, cc: gcc-11, cxx: g++-11 }
          - { os: ubuntu-latest, cc: gcc-12, cxx: g++-12 }
          - { os: ubuntu-latest, cc: gcc-13, cxx: g++-13 }
          - { os: ubuntu-20.04, cc: clang-8, cxx: clang++-8 }
          - { os: ubuntu-20.04, cc: clang-9, cxx: clang++-9 }
          - { os: ubuntu-20.04, cc: clang-10, cxx: clang++-10 }
          - { os: ubuntu-20.04, cc: clang-11, cxx: clang++-11 }
          - { os: ubuntu-20.04, cc: clang-12, cxx: clang++-12 }
          - { os: ubuntu-latest, cc: clang-13, cxx: clang++-13 }
          - { os: ubuntu-latest, cc: clang-14, cxx: clang++-14 }
          - { os: ubuntu-latest, cc: clang-15, cxx: clang++-15 }

    env:
      CC: ${{ matrix.target.cc }}
      CXX: ${{ matrix.target.cxx }}

    steps:
      - uses: actions/checkout@v4

      - name: install compiler
        run: |
          sudo apt-get update
          sudo apt-get install -y ${{ matrix.target.cc }}
          sudo apt-get install -y ${{ matrix.target.cxx }}
      
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs (debug)
        run: |
          bake --strict --cfg debug

      - name: build flecs (release)
        run: |          
          bake --strict --cfg release

      - name: build examples (debug)
        run: |
          bake examples/c --strict --cfg debug
          bake examples/cpp --strict --cfg debug
          bake examples/os_api --strict --cfg debug

      - name: build examples (release)
        run: |
          bake examples/c --strict --cfg release
          bake examples/cpp --strict --cfg release
          bake examples/os_api --strict --cfg release

  build-cmake:
    needs: build-linux
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macOS-latest, macOS-14 ]

    steps:
      - uses: actions/checkout@v4

      - name: create cmake build folders
        run: |
          mkdir cmake_build
          mkdir examples/c/cmake_build
          mkdir examples/cpp/cmake_build

      - name: build flecs
        working-directory: cmake_build
        run: |
          cmake -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c examples
        working-directory: examples/c/cmake_build
        run: |
          cmake -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c++ examples
        working-directory: examples/cpp/cmake_build
        run: |
          cmake -DFLECS_STRICT=ON ..
          cmake --build . -j 4

  build-cmake-windows:
    needs: build-windows
    runs-on: windows-latest
    timeout-minutes: 30

    strategy:
      matrix:
        toolset: [default, v141, v142, clang-cl]
        include:
          - toolset: v141
            toolset_option: -T"v141"
          - toolset: v142
            toolset_option: -T"v142"
          - toolset: clang-cl
            toolset_option: -T"ClangCl"

    steps:
      - uses: actions/checkout@v4
      - name: create cmake build folders
        run: |
          mkdir cmake_build
          mkdir examples/c/cmake_build
          mkdir examples/cpp/cmake_build

      - name: build flecs
        working-directory: cmake_build
        run: |
          cmake ${{ matrix.toolset_option }} -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c examples
        working-directory: examples/c/cmake_build
        run: |
          cmake ${{ matrix.toolset_option }} -DFLECS_STRICT=ON ..
          cmake --build . -j 4

      - name: build c++ examples
        working-directory: examples/cpp/cmake_build
        run: |
          cmake ${{ matrix.toolset_option }} -DFLECS_STRICT=ON ..
          cmake --build . -j 4

  build-meson:
    needs: build-linux
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4

      - name: install meson
        run: |
          pip3 install meson
          pip3 install ninja==1.10.2.4
        
      - name: create build folder
        run: meson meson_build

      - name: build flecs
        working-directory: meson_build
        run: |
          meson compile

  build-custom:
    needs: build-linux
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        compiler: [ gcc, clang ]

    steps:
      - uses: actions/checkout@v4
      - name: Install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: FLECS_SOFT_ASSERT flag
        run: |
          bake rebuild --strict -D FLECS_SOFT_ASSERT
          bake rebuild --strict --cfg release -D FLECS_SOFT_ASSERT

      - name: FLECS_KEEP_ASSERT flag
        run: |
          bake rebuild --strict -D FLECS_KEEP_ASSERT
          bake rebuild --strict --cfg release -D FLECS_KEEP_ASSERT

      - name: no extensions
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD

      - name: FLECS_SYSTEM
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_SYSTEM
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_SYSTEM

      - name: FLECS_PIPELINE
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_PIPELINE
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_PIPELINE

      - name: FLECS_TIMER
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_TIMER
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_TIMER

      - name: FLECS_MODULE
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_MODULE
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_MODULE

      - name: FLECS_SNAPSHOT
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_SNAPSHOT
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_SNAPSHOT

      - name: FLECS_STATS
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_STATS
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_STATS

      - name: FLECS_PARSER
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_PARSER
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_PARSER

      - name: FLECS_PLECS
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_PLECS
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_PLECS

      - name: FLECS_META
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_META
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_META

      - name: FLECS_META_C
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_META_C
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_META_C

      - name: FLECS_EXPR
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_EXPR
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_EXPR

      - name: FLECS_JSON
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_JSON
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_JSON

      - name: FLECS_DOC
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_DOC
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_DOC

      - name: FLECS_COREDOC
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_COREDOC
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_COREDOC

      - name: FLECS_LOG
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_LOG
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_LOG

      - name: FLECS_APP
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_APP
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_APP

      - name: FLECS_OS_API_IMPL
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_OS_API_IMPL
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_OS_API_IMPL

      - name: FLECS_HTTP
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_HTTP
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_HTTP

      - name: FLECS_REST
        run: |
          bake rebuild --strict -D FLECS_CUSTOM_BUILD -D FLECS_REST
          bake rebuild --strict --cfg release -D FLECS_CUSTOM_BUILD -D FLECS_REST

      - name: FLECS_NO_LOG
        run: |
          bake rebuild --strict -D FLECS_NO_LOG
          bake rebuild --strict --cfg release -D FLECS_NO_LOG

      - name: FLECS_DEFAULT
        run: |
          bake rebuild --strict
          bake rebuild --strict --cfg release

      - name: custom_build tests
        run: |
          bake rebuild test/custom_builds --strict
          bake runall test/custom_builds

  build-amalgamated:
    needs: build-linux
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        compiler: [ gcc, clang ]

    steps:
      - uses: actions/checkout@v4
      - name: build flecs
        run: ${{ matrix.compiler }} flecs.c --shared -fPIC -pedantic -Wall -Wextra -Wno-unused-parameter -Werror -Wshadow -Wconversion -Wno-missing-field-initializers

  build-scan-build:
    needs: build-linux
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4

      - name: install clang-build
        run: |
          sudo apt-get install -y clang-tools   
      
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: run scan-build
        run: |
          scan-build --status-bugs bake

  test-c-unix:
    needs: [build-linux, build-macos]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macOS-latest, macOS-14 ]

    steps:
      - uses: actions/checkout@v4

      - name: compiler version
        run: |
          gcc --version
          clang --version

      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: test api
        run: bake run test/api -- -j 8

      - name: test addons
        run: bake run test/addons -- -j 8

      - name: test meta
        run: bake run test/meta -- -j 8

      - name: test collections
        run: bake run test/collections -- -j 8

  test-cpp-unix:
    needs: [build-linux]
    runs-on: ${{ matrix.target.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        target:
          - { os: ubuntu-20.04, cc: gcc-9,  cxx: g++-9 }
          - { os: ubuntu-20.04, cc: gcc-10, cxx: g++-10 }
          - { os: ubuntu-20.04, cc: gcc-11, cxx: g++-11 }
          - { os: ubuntu-latest, cc: gcc-12, cxx: g++-12 }
          - { os: ubuntu-latest, cc: gcc-13, cxx: g++-13 }
          - { os: ubuntu-20.04, cc: clang-8, cxx: clang++-8 }
          - { os: ubuntu-20.04, cc: clang-9, cxx: clang++-9 }
          - { os: ubuntu-20.04, cc: clang-10, cxx: clang++-10 }
          - { os: ubuntu-20.04, cc: clang-11, cxx: clang++-11 }
          - { os: ubuntu-20.04, cc: clang-12, cxx: clang++-12 }
          - { os: ubuntu-latest, cc: clang-13, cxx: clang++-13 }
          - { os: ubuntu-latest, cc: clang-14, cxx: clang++-14 }
          - { os: ubuntu-latest, cc: clang-15, cxx: clang++-15 }

    env:
      CC: ${{ matrix.target.cc }}
      CXX: ${{ matrix.target.cxx }}

    steps:
      - uses: actions/checkout@v4

      - name: install compiler
        run: |
          sudo apt-get update
          sudo apt-get install -y ${{ matrix.target.cc }}
          sudo apt-get install -y ${{ matrix.target.cxx }}

      - name: compiler version
        run: |
          ${{ matrix.target.cc }} --version
          ${{ matrix.target.cxx }} --version

      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: test c++
        run: bake run test/cpp_api -- -j 8

  test-cpp-macos:
    needs: [build-macos]
    runs-on: ${{ matrix.os.version }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: 
          - { version: macOS-11, xcode: '11.7' }
          - { version: macOS-11, xcode: '12.4' }
          - { version: macOS-11, xcode: '13.0' }
          - { version: macOS-12, xcode: '13.1' }
          - { version: macOS-12, xcode: '14.0' }
          - { version: macOS-14, xcode: '15.2' }

    env:
      CC: clang
      CXX: clang++

    steps:
      - uses: actions/checkout@v4

      - uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: ${{ matrix.os.xcode }}

      - name: compiler version
        run: |
          clang --version

      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: test c++
        run: bake run test/cpp_api -- -j 8

  test-windows:
    needs: build-windows
    runs-on: windows-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      - uses: ilammy/msvc-dev-cmd@v1
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          cd bake\build-Windows
          nmake
          cd ..
          ./bake setup --local

      - name: build flecs
        run: bake/bake

      - name: test api
        run: bake/bake run test\api -- -j 8

      - name: test addons
        run: bake/bake run test\addons -- -j 8

      - name: test meta
        run: bake/bake run test\meta -- -j 8

      - name: test collections
        run: bake/bake run test\collections -- -j 8

      - name: test c++
        run: bake/bake run test\cpp_api -- -j 8

  test-msys:
    runs-on: windows-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        include:
          - { sys: mingw64 }
          - { sys: mingw32 }
          - { sys: ucrt64 }
          - { sys: clang64 }

    defaults:
      run:
        shell: msys2 {0}

    steps:
      - uses: actions/checkout@v4
      - uses: msys2/setup-msys2@v2
        with:
          msystem: ${{matrix.sys}}
          update: true
          install: >-
            curl
            git
          pacboy: >-
            toolchain:p
            cmake:p

      - name: install bake
        run: |
          cp `which mingw32-make` /usr/bin/make
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-Mingw
          bake/bake setup

      - name: build flecs
        run: bake/bake --strict

      - name: test api
        run: bake/bake run test/api -- -j 8

      - name: test addons
        run: bake/bake run test/addons -- -j 8

      - name: test meta
        run: bake/bake run test/meta -- -j 8

      - name: test collections
        run: bake/bake run test/collections -- -j 8

      - name: test c++
        run: bake/bake run test/cpp_api -- -j 8

  test-sanitized-api:
    needs: [ build-linux ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]

    steps:
      - uses: actions/checkout@v4
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: run tests
        run: |
          bake run test/api --cfg sanitize -- -j 8

  test-sanitized-addons:
    needs: [ build-linux ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]

    steps:
      - uses: actions/checkout@v4
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: run tests
        run: |
          bake run test/addons --cfg sanitize -- -j 8

  test-sanitized-meta:
    needs: [ build-linux ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]

    steps:
      - uses: actions/checkout@v4
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: run tests
        run: |
          bake run test/meta --cfg sanitize -- -j 8

  test-sanitized-collections:
    needs: [ build-linux ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]

    steps:
      - uses: actions/checkout@v4
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: run tests
        run: |
          bake run test/collections --cfg sanitize -- -j 8

  test-sanitized-cpp_api:
    needs: [ build-linux ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]

    steps:
      - uses: actions/checkout@v4
      - name: install bake
        run: |
          git clone https://github.com/SanderMertens/bake
          make -C bake/build-$(uname)
          bake/bake setup

      - name: build flecs
        run: bake --strict

      - name: run tests
        run: |
          bake run test/cpp_api --cfg sanitize -- -j 8

  test-cmake:
    needs: [ build-linux, build-macos ]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macOS-latest, macOS-14 ]

    steps:
      - uses: actions/checkout@v4
      - name: clone bake
        run: |
          git clone https://github.com/SanderMertens/bake

      - name: build flecs & tests
        run: |
          cmake -DFLECS_TESTS=ON -DBAKE_DIRECTORY=bake
          cmake --build . -j 4

      - name: run tests
        run: |
          ctest -C Debug --verbose
